package cn.bigfire.wedesk.util;

import cn.bigfire.wedesk.net.codec.ProtocolDecoder;
import cn.bigfire.wedesk.net.codec.ProtocolEncoder;
import cn.bigfire.wedesk.net.fivesocket.codec.FiveSocketDecoder;
import cn.bigfire.wedesk.net.fivesocket.codec.FiveSocketEncoder;
import cn.bigfire.wedesk.net.initializer.TcpClientChannelInitializer;
import cn.bigfire.wedesk.net.protocol.CmdMapper;
import cn.bigfire.wedesk.net.protocol.TypeMapper;
import cn.bigfire.wedesk.util.portsanner.PortIps;
import cn.bigfire.wedesk.util.portsanner.PortScanner;
import cn.hutool.core.net.NetUtil;
import com.alibaba.fastjson.JSON;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/*
开放一个8808端口用于内网其他主机连接
构建一个map存放控制端连接
 */
public class Seeker {

    public static final String serverIp = "101.34.7.208";
    public static final int serverPort = 54320;
    public static final int lanPort = 8808;
    public static Channel serverChannel;
    public static HashMap<String, Channel> serverChannelMaps = new HashMap<>();
    public static void start(){
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);
        scheduledThreadPool.scheduleAtFixedRate(() -> {
            //外网服务器
            if (serverChannel == null && NetUtil.isOpen(NetUtil.buildInetSocketAddress(serverIp, serverPort), 1000)) {
                serverChannel = TcpUtil.clientConnect(serverIp, serverPort, new TcpClientChannelInitializer());
                if (serverChannel == null) {
                    System.err.println("连接服务器失败,程序终止");
                }
            }

            //内网
            PortIps portIps = PortScanner.scanIpByPort(lanPort);
            CopyOnWriteArrayList<String> lanIpList = portIps.getIpList();//内网开放端口的服务器列表
            for (String lanIp : lanIpList) {
                if (!lanIp.equals(NetUtil.getLocalhostStr()) && !serverChannelMaps.containsKey(lanIp)) {
                    Channel lanChannel = TcpUtil.clientConnect(lanIp, lanPort, new TcpClientChannelInitializer());
                    if (lanChannel != null) {
                        serverChannelMaps.put(lanIp, lanChannel);
                    }
                }
            }
            System.out.printf("30 seconds check server:%s,lanIpList:%s,%n", serverChannel != null ? "ok" : "err", JSON.toJSONString(lanIpList));
        }, 30, 30, TimeUnit.SECONDS);//半分钟检查一次


        ChannelInitializer<NioSocketChannel> channelInitializer = new ChannelInitializer<NioSocketChannel>() {
            @Override
            protected void initChannel(NioSocketChannel channel) throws Exception {
                channel.pipeline().addLast(new FiveSocketDecoder());//应用层解码器
                channel.pipeline().addLast(new FiveSocketEncoder());//应用层编码器
                channel.pipeline().addLast(new ProtocolDecoder());//业务层解码器
                channel.pipeline().addLast(new ProtocolEncoder());//业务层编码器
                //不应该用服务器的ServerHandler，而应该自己构建自己的处理器
//                channel.pipeline().addLast(new ServerHandler());
            }
        };

        TcpUtil.serverStart(lanPort, channelInitializer);
        List<Integer> cmdList = new ArrayList<>(CmdMapper.methodMapper.keySet());
        List<Integer> typeList =  new ArrayList<>(TypeMapper.type2ClassMap.keySet());
        Collections.sort(cmdList);
        Collections.sort(typeList);
        System.out.println("成功注册协议号:" + JSON.toJSONString(cmdList));
        System.out.println("成功注册类型:" + JSON.toJSONString(typeList));

    }


    public static void main(String[] args) {
        start();
    }

}
